﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;

using System.Diagnostics;
using System.Collections;
using System.Collections.ObjectModel;
using System.ComponentModel;
using SqlMiM.ReportingServices;
using System.Windows.Threading;
using System.IO;
using SqlMiM.ReportingServices.ReportExportPlugin;
using SqlMiM.ReportingServices.SqlRs;
using SqlMiM.ReportingServices.Core;
using System.Windows.Forms;
using SqlMiM.Common.ViewModel;
using SqlMiM.Common.Commands;
using MvvmFoundation.Wpf;

namespace SqlMiM.ReportingServices.ReportImportPlugin
{
    public class ViewModel : ObservableObject
    {
        private SqlRs.ReportingService2005 rs;
        private BackgroundWorker workerWriterCatalog;
        private String webServiceUrl;
        private string inputDirectory;
        private bool isLoadingCatalog;
        private bool isFirstLoad;
        private bool isGenerating;
        private ObservableCollection<CatalogItemViewModel> catalog;
        private ObservableCollection<ResultWarningViewModel> resultWarnings;
        private RelayCommand refrehCatalogCommand;
        private RelayCommand navigateWebServiceCommand;
        private RelayCommand inputDirectoryCommand;
        private RelayCommand importCatalogCommand;

        /// <summary>
        /// Constructor
        /// </summary>
        public ViewModel()
        {

            this.WebServiceUrl = RS.Current.GetReportingServicesWebServiceUrl();
            this.IsLoadingCatalog = false;
            this.IsFirstLoad = true;
            this.IsGenerating = false;
            this.ResultWarnings = new ObservableCollection<ResultWarningViewModel>();
        }

        /// <summary>
        /// Reporting Service Web Url;
        /// </summary>
        public String WebServiceUrl
        {
            get
            {
                return webServiceUrl;
            }
            set
            {
                webServiceUrl = value;
                this.RaisePropertyChanged("WebServiceUrl");
            }
        }

        /// <summary>
        /// OutPutDirectory 
        /// </summary>
        public string InputDirectory
        {
            get { return inputDirectory; }
            set
            {
                inputDirectory = value;
                this.RaisePropertyChanged("InputDirectory");
            }
        }

        /// <summary>
        /// Catalog is Loading
        /// </summary>
        public bool IsLoadingCatalog
        {
            get { return isLoadingCatalog; }
            set
            {
                isLoadingCatalog = value;
                this.RaisePropertyChanged("IsLoadingCatalog");
            }
        }

        /// <summary>
        /// View is loaded and no load on catalog has been made.
        /// </summary>
        public bool IsFirstLoad
        {
            get { return isFirstLoad; }
            set
            {
                isFirstLoad = value;
                this.RaisePropertyChanged("IsFirstLoad");
            }
        }

        /// <summary>
        /// View is generating files
        /// </summary>
        public bool IsGenerating
        {
            get { return isGenerating; }
            set
            {
                isGenerating = value;
                this.RaisePropertyChanged("IsGenerating");
            }
        }

        /// <summary>
        /// Items Catalog
        /// </summary>
        public ObservableCollection<CatalogItemViewModel> Catalog
        {
            get { return catalog; }
            set
            {
                catalog = value;
                this.RaisePropertyChanged("Catalog");
            }
        }

        /// <summary>
        /// Items Catalog
        /// </summary>
        public ObservableCollection<ResultWarningViewModel> ResultWarnings
        {
            get { return resultWarnings; }
            set
            {
                resultWarnings = value;
                this.RaisePropertyChanged("ResultWarnings");
            }
        }

        /// <summary>
        /// Returns a command that saves the customer.
        /// </summary>
        public ICommand NavigateWebServiceCommand
        {
            get
            {
                if (navigateWebServiceCommand == null)
                {
                    navigateWebServiceCommand = new RelayCommand(this.NavigateWebServiceUrl, this.CanNavigateWebServiceUrl);

                }
                return navigateWebServiceCommand;
            }
        }

        /// <summary>
        /// Returns a command that saves the customer.
        /// </summary>
        public ICommand RefrehCatalogCommand
        {
            get
            {
                if (refrehCatalogCommand == null)
                {
                    refrehCatalogCommand = new RelayCommand(this.RefreshCatalog, this.CanNavigateWebServiceUrl);

                }
                return refrehCatalogCommand;
            }
        }

        /// <summary>
        /// Returns a command that saves the customer.
        /// </summary>
        public ICommand InputDirectoryCommand
        {
            get
            {
                if (inputDirectoryCommand == null)
                {
                    inputDirectoryCommand = new RelayCommand(this.GetInputDirectoryCommand);

                }
                return inputDirectoryCommand;
            }
        }

        /// <summary>
        /// Write catalog (all checked items)
        /// </summary>
        public ICommand ImportCatalogCommand
        {
            get
            {
                if (importCatalogCommand == null)
                {
                    importCatalogCommand = new RelayCommand(this.ImportCatalog, this.CanImportCatalog);

                }
                return importCatalogCommand;
            }
        }


        /// <summary>
        /// Navigate to Web Service url
        /// </summary>
        /// <returns></returns>
        private void NavigateWebServiceUrl()
        {
            String navigateUri = this.WebServiceUrl;
            Process.Start(new ProcessStartInfo(navigateUri));
        }

        /// <summary>
        /// Check if WebService is filled
        /// </summary>
        /// <returns></returns>
        private bool CanNavigateWebServiceUrl()
        {
            return !string.IsNullOrEmpty(this.WebServiceUrl);
        }

        /// <summary>
        /// Load catalog
        /// </summary>
        private void RefreshCatalog()
        {
            this.IsLoadingCatalog = true;
            this.IsFirstLoad = false;

            var worker = new BackgroundWorker();

            worker.DoWork += (sender, e) =>
            {
                List<CatalogItemViewModel> lst = GetRecursiveCatalogItems(null, this.WebServiceUrl, "/");

                if (lst != null)
                {
                    this.Catalog = new ObservableCollection<CatalogItemViewModel>(lst);
                }

            };

            worker.RunWorkerCompleted += (sender, e) =>
            {
                this.IsLoadingCatalog = false;
            };

            worker.RunWorkerAsync();
        }

        /// <summary>
        /// Get All Items recursively
        /// </summary>
        private List<CatalogItemViewModel> GetRecursiveCatalogItems(CatalogItemViewModel parent, string url, string path)
        {
            List<CatalogItemViewModel> lst = new List<CatalogItemViewModel>();

            var items = RS.Current.GetChildrenItems(url, path);

            if (items != null)
            {
                foreach (var item in items)
                {
                    CatalogItemViewModel civm = new CatalogItemViewModel(item);
                    civm.Parent = parent;

                    // If it's a folder, go Recusive get sub items.
                    if (civm.Type == ItemTypeEnum.Folder)
                    {
                        var childs = GetRecursiveCatalogItems(civm, url, civm.Path);
                        if (childs != null)
                        {
                            civm.Childrens = new ObservableCollection<CatalogItemViewModel>(childs);
                        }
                    }

                    lst.Add(civm);
                }
            }

            return lst;
        }

        /// <summary>
        /// Get an output directory
        /// </summary>
        /// <returns></returns>
        private void GetInputDirectoryCommand()
        {
            FolderBrowserDialog folderBrowserDialog = new FolderBrowserDialog();

            if (!String.IsNullOrEmpty(this.InputDirectory))
            {
                folderBrowserDialog.SelectedPath = this.InputDirectory;
            }

            if (folderBrowserDialog.ShowDialog() == DialogResult.OK)
            {
                this.InputDirectory = folderBrowserDialog.SelectedPath;
            }
        }


        /// <summary>
        /// Get if we can write catalog
        /// </summary>
        /// <returns></returns>
        private bool CanImportCatalog()
        {
            // Cant generate when :
            //  Already in generating progress
            //  No catalog loaded
            //  Catalog empty
            return !this.IsGenerating && !this.IsLoadingCatalog && !String.IsNullOrEmpty(this.InputDirectory);
        }

        /// <summary>
        /// Write all checked items
        /// </summary>
        private void ImportCatalog()
        {

            this.IsGenerating = true;
            this.ResultWarnings = new ObservableCollection<ResultWarningViewModel>();

            workerWriterCatalog = new BackgroundWorker();
            workerWriterCatalog.WorkerReportsProgress = true;

            workerWriterCatalog.DoWork += AsyncImportCatalog;

            workerWriterCatalog.ProgressChanged += AsyncImportCatalog_ProgressChanged;

            workerWriterCatalog.RunWorkerCompleted += delegate(object sender, RunWorkerCompletedEventArgs e)
            {
                this.IsGenerating = false;
                this.RefreshCatalog();
                workerWriterCatalog.Dispose();
            };

            workerWriterCatalog.RunWorkerAsync();
        }



        private void AsyncImportCatalog_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            // Add result to list ..
            this.ResultWarnings.Add(e.UserState as ResultWarningViewModel);

        }

        private void AsyncImportCatalog(object sender, DoWorkEventArgs e)
        {
            // Reporting Service Instance
            var rs = new ReportingService2005();
            rs.Url = webServiceUrl;
            // Set Credentials
            rs.Credentials = System.Net.CredentialCache.DefaultCredentials;

            DirectoryInfo dir = new DirectoryInfo(this.InputDirectory);

            // Write all items
            RecurseImportFolders(rs, dir, "/", e);
            RecurseImportDatasources(rs, dir, "/", e);
            RecurseImportRessources(rs, dir, "/", e);
            RecurseImportReports(rs, dir, "/", e);
        }

        /// <summary>
        /// Write all catalog to file system
        /// </summary>
        private void RecurseImportFolders(ReportingService2005 rs, DirectoryInfo physicalParentDir, String virtualParentDir, DoWorkEventArgs e)
        {

            // Create directories
            if (physicalParentDir.GetDirectories() != null)
            {
                foreach (DirectoryInfo di in physicalParentDir.GetDirectories())
                {
                    var result = RS.Current.ImportDirectory(rs, di.FullName, di.Name, virtualParentDir);

                    var r = new ResultWarningViewModel(result, ItemTypeEnum.Folder);

                    workerWriterCatalog.ReportProgress(0, r);


                    if (di.GetDirectories() != null)
                    {
                        // New virtual parent dir path
                        string virtualDir = String.Concat(virtualParentDir, di.Name);
                        RecurseImportFolders(rs, di, virtualDir, e);
                    }
                }
            }
        }

        /// <summary>
        /// Write all catalog to file system
        /// </summary>
        private void RecurseImportDatasources(ReportingService2005 rs, DirectoryInfo physicalParentDir, String virtualParentDir, DoWorkEventArgs e)
        {

            // Create directories
            if (physicalParentDir.GetFiles("*.rds") != null && physicalParentDir.GetFiles("*.rds").Length > 0)
            {
                foreach (var file in physicalParentDir.GetFiles("*.rds"))
                {
                    var dsName = file.Name.Replace(file.Extension, String.Empty);

                    var result = RS.Current.ImportDataSource(rs, file.FullName, dsName, virtualParentDir);

                    var r = new ResultWarningViewModel(result, ItemTypeEnum.DataSource);

                    workerWriterCatalog.ReportProgress(0, r);
                }
            }

            if (physicalParentDir.GetDirectories() != null && physicalParentDir.GetDirectories().Length > 0)
            {
                foreach (var dir in physicalParentDir.GetDirectories())
                {
                    String newVirtualParentDir = virtualParentDir;

                    if (newVirtualParentDir.EndsWith(@"/"))
                        newVirtualParentDir = newVirtualParentDir.Remove(newVirtualParentDir.LastIndexOf(@"/"), 1);

                    newVirtualParentDir = String.Concat(virtualParentDir, dir.Name);

                    RecurseImportDatasources(rs, dir, newVirtualParentDir, e);
                }
            }
        }

        /// <summary>
        /// Write all catalog to file system
        /// </summary>
        private void RecurseImportReports(ReportingService2005 rs, DirectoryInfo physicalParentDir, String virtualParentDir, DoWorkEventArgs e)
        {

            // Create directories
            if (physicalParentDir.GetFiles("*.rdl") != null && physicalParentDir.GetFiles("*.rdl").Length > 0)
            {
                foreach (var file in physicalParentDir.GetFiles("*.rdl"))
                {
                    var dsName = file.Name.Replace(file.Extension, String.Empty);

                    var result = RS.Current.ImportReport(rs, file.FullName, dsName, virtualParentDir);

                    var r = new ResultWarningViewModel(result, ItemTypeEnum.Report);

                    workerWriterCatalog.ReportProgress(0, r);
                }
            }

            if (physicalParentDir.GetDirectories() != null && physicalParentDir.GetDirectories().Length > 0)
            {
                foreach (var dir in physicalParentDir.GetDirectories())
                {
                    String newVirtualParentDir = virtualParentDir;

                    if (newVirtualParentDir.EndsWith(@"/"))
                        newVirtualParentDir = newVirtualParentDir.Remove(newVirtualParentDir.LastIndexOf(@"/"), 1);

                    newVirtualParentDir = String.Concat(virtualParentDir, dir.Name);

                    RecurseImportReports(rs, dir, newVirtualParentDir, e);
                }
            }
        }

        /// <summary>
        /// Write all catalog to file system
        /// </summary>
        private void RecurseImportRessources(ReportingService2005 rs, DirectoryInfo physicalParentDir, String virtualParentDir, DoWorkEventArgs e)
        {

            // Create directories
            if (physicalParentDir.GetFiles("*.resx") != null && physicalParentDir.GetFiles("*.resx").Length > 0)
            {
                foreach (var file in physicalParentDir.GetFiles("*.resx"))
                {
                    var dsName = file.Name.Replace(file.Extension, String.Empty);

                    var result = RS.Current.ImportRessource(rs, file.FullName, dsName, virtualParentDir);

                    var r = new ResultWarningViewModel(result, ItemTypeEnum.Resource);

                    workerWriterCatalog.ReportProgress(0, r);
                }
            }

            if (physicalParentDir.GetDirectories() != null && physicalParentDir.GetDirectories().Length > 0)
            {
                foreach (var dir in physicalParentDir.GetDirectories())
                {
                    String newVirtualParentDir = virtualParentDir;

                    if (newVirtualParentDir.EndsWith(@"/"))
                        newVirtualParentDir = newVirtualParentDir.Remove(newVirtualParentDir.LastIndexOf(@"/"), 1);

                    newVirtualParentDir = String.Concat(virtualParentDir, dir.Name);

                    RecurseImportRessources(rs, dir, newVirtualParentDir, e);
                }
            }
        }




        //    foreach (CatalogItemViewModel civm in subCatalog)
        //    {
        //        if (civm.IsChecked.HasValue && civm.IsChecked.Value)
        //        {
        //            ResultWarning result = null;

        //            switch (civm.Type)
        //            {
        //                case ItemTypeEnum.Folder:
        //                    result = RS.Current.CreateDirectory(rs, civm.Item, this.InputDirectory);
        //                    break;
        //                case ItemTypeEnum.DataSource:
        //                    result = RS.Current.CreateDataSource(rs, civm.Item, this.InputDirectory);
        //                    break;
        //                case ItemTypeEnum.LinkedReport:
        //                    break;

        //                case ItemTypeEnum.Model:
        //                    result = RS.Current.CreateModel(rs, civm.Item, this.InputDirectory);
        //                    break;
        //                case ItemTypeEnum.Report:
        //                    result = RS.Current.CreateReport(rs, civm.Item, this.InputDirectory);
        //                    break;
        //                case ItemTypeEnum.Resource:
        //                    result = RS.Current.CreateRessource(rs, civm.Item, this.InputDirectory);
        //                    break;
        //                case ItemTypeEnum.Unknown:
        //                    break;
        //                default:
        //                    break;
        //            }

        //            var r = new ResultWarningViewModel(result, civm.Item);

        //            workerWriterCatalog.ReportProgress(0, r);

        //            if (civm.Childrens != null && civm.Childrens.Count > 0)
        //                RecurseImportCatalog(rs, civm.Childrens, e);

        //        }
        //    }
    }
}
